#include "device.h"
#include "component.h"
#include <stdio.h>
#include <stdlib.h>
#include "math.h"

/* 调试打印接口 */
#define PIR_LOG(format, ...) OSAL_LOG(C_CYAN format C_NONE, ##__VA_ARGS__)
#define __PIR_LOG(format, ...) //__OSAL_LOG(C_CYAN format C_NONE, ##__VA_ARGS__)

/* 虚拟硬件接口 */
#define VHW_ADC_PIR vADC_2
#define VHW_IRQ_PIR vPIN_I2

#define EVENT_PIR_START                     (0x00000001)
#define EVENT_PIR_PRO                       (0x00000002)

#define PIR_NEAR_DETECTION_THRESHOLD    100	/* 人接近检测阀值 */
#define PIR_HOVER_DETECTION_THRESHOLD   60  /* 人徘徊检测阀值 */
#define PIR_LONG_TERM_FILTER_RANGE      16	/* 长期过滤器长度 */
#define PIR_SHORT_TERM_FILTER_RANGE     4   /* 短期过滤器长度 */
#define PIR_IRQ_THRESHOLD               4   /* 人体接近PIR中断次数阀值 */
#define PIR_IRQ_HOVER_THRESHOLD         16  /* 徘徊检测中断次数阀值 */

__NVRAM volatile static int32_t accumulated_long_term_average = 0;     /* 长器过滤器累积值，缓慢变化 */
__NVRAM volatile static int16_t accumulated_short_term_average = 0;    /* 短效过滤器积值，快速变化 */

/**
 * @brief: 读取PIR的电压值
 * @note:
 * @param {*}
 * @return {*}
 */
static uint16_t PIR_GetVoltage(void)
{
    uint16_t voltage = (uint16_t)Device_Read(VHW_ADC_PIR, NULL, 0, 0);
    return voltage; 
}

/**
 * @brief: 读PIR中断IO的电平
 * @note: 
 * @param {*}
 * @return {*}
 */
static bool PIR_ReadGPIO()
{
    if (Device_Read(vPIN_I2,NULL,0,0) == 0)
    {
        return false;
    }    
    else 
    {
        return true;
    }
}

/**
 * @brief: 计算增量值
 * @note: 
 * @param {int32_t} long_term 长期累积值
 * @param {int16_t} short_term 短期累积值
 * @return {*}
 */
static int16_t PIR_CalIncrement(int32_t long_term,int16_t short_term)
{
    int16_t long_val = long_term / PIR_LONG_TERM_FILTER_RANGE;
    int16_t short_val = short_term / PIR_SHORT_TERM_FILTER_RANGE;
    return (int16_t)(long_val - short_val);
}

/**
  * @brief  INT引脚中断回调
  *         
  * @note   在中断里面执行的，这里一般设置ISR事件即可，不要做过多的逻辑
  */
static void Pir_IrqHandle(VirtualHardware_enum_t dev, void *data, uint32_t len)
{
    static uint8_t pir_irq_cnt = 0;
    uint16_t adc_result = PIR_GetVoltage();
    accumulated_short_term_average -= (accumulated_short_term_average / PIR_SHORT_TERM_FILTER_RANGE); 
	accumulated_short_term_average += adc_result; 
    printf(" %d\r\n",PIR_CalIncrement(accumulated_long_term_average,accumulated_short_term_average));
    if (abs(PIR_CalIncrement(accumulated_long_term_average,accumulated_short_term_average)) >= PIR_NEAR_DETECTION_THRESHOLD)
    {
        if (++pir_irq_cnt >= PIR_IRQ_THRESHOLD)
        {
            pir_irq_cnt = 0;
            printf("people near\r\n");   
        }
    }
    else
    {
        pir_irq_cnt = 0;   
    }
}

/**
 * @brief: 更新长期过滤器和短期过滤器的累加值。
 * @note: 1、定期更新过滤器，从长期过滤器中换出 1/16
          2、每次ADC 进行新的测量时，短期滤波器的 1/4
          3、当 PIR 的输出稳定时，滤波器值将彼此接近。
          4、当运动发生时，短期过滤器将快速响应变化
 * @param {*}
 * @return {*}
 */
static void Update_AverageFilters()
{
    uint16_t adc_result = PIR_GetVoltage();
    if (PIR_ReadGPIO() == false)//中断脚在低电平时才更新长期累积值
    {
        accumulated_long_term_average -= (accumulated_long_term_average / PIR_LONG_TERM_FILTER_RANGE); 
        accumulated_long_term_average += adc_result;  
    }
	accumulated_short_term_average -= (accumulated_short_term_average / PIR_SHORT_TERM_FILTER_RANGE); 
	accumulated_short_term_average += adc_result; 

    // printf(" %d\r\n",PIR_CalIncrement(accumulated_long_term_average,accumulated_short_term_average));
}

/**
 * @brief: 初始化长效短效累积值
 * @note: 第一次上电的时候调用
 * @param {*}
 * @return {*}
 */
static void Warm_UpAnd_FilterCreation(void)
{
    static uint8_t i = 0;
    if (i < PIR_LONG_TERM_FILTER_RANGE)
    {
        uint16_t adc_result = PIR_GetVoltage();
        accumulated_long_term_average = accumulated_long_term_average + adc_result;
        if (i < PIR_SHORT_TERM_FILTER_RANGE)
        {
            accumulated_short_term_average = accumulated_short_term_average + adc_result;   
        }
    }

    if (i < PIR_LONG_TERM_FILTER_RANGE)
    {
        i++;
    }
    else    /* 初始化完成 */
    {
        OSAL_EventRepeatCreate(COMP_PIR,EVENT_PIR_PRO,30,EVT_PRIORITY_LOW);  
        OSAL_EventDelete(COMP_PIR,EVENT_PIR_START);
    }
}

/**
  * @brief  唤醒回调
  *         
  * @note   休眠状态下INT触发：会执行这个CB
  * @return 返回0：不唤醒， 返回非0：唤醒
  */
static int32_t Pir_WakeHandle(uint32_t dev)
{
    __NVRAM static uint8_t irq_near_thead = 0;
    __NVRAM static uint32_t irq_hover_thead = 0;
    int16_t filter_delta = 0;
    uint16_t adc_result = PIR_GetVoltage();
    accumulated_short_term_average -= (accumulated_short_term_average / PIR_SHORT_TERM_FILTER_RANGE); 
    accumulated_short_term_average += adc_result; 
    filter_delta = PIR_CalIncrement(accumulated_long_term_average,accumulated_short_term_average);
    printf("filter_delta:%d\r\n",filter_delta);
    irq_near_thead <= 1;
    irq_hover_thead <= 1;
    if (abs(filter_delta) >= PIR_NEAR_DETECTION_THRESHOLD)//检测人体靠近
    {
        irq_near_thead |= 1;
        if ((irq_near_thead & (~(0xff << PIR_IRQ_THRESHOLD))) == (~(0xff << PIR_IRQ_THRESHOLD)))
        {
            //TODO 人体接近，唤醒系统
            printf("wakeup\r\n");
            return 1;
        }
    }
    else if (abs(filter_delta) >= PIR_HOVER_DETECTION_THRESHOLD)//检测徘徊
    {
        irq_hover_thead |= 1;
        if ((irq_hover_thead & (~(0xffffffff << PIR_IRQ_HOVER_THRESHOLD))) == (~(0xffffffff << PIR_IRQ_HOVER_THRESHOLD)))
        {
            //TODO 徘徊报警
            printf("hover alarm\r\n");
            return 1;
        }
    }
    else
    {
        irq_near_thead &= 0xFE; 
        irq_hover_thead &= 0xFFFFFFFE; 
    }
    return 0;
}
COMPONENT_WAKEUP_EXPORT(COMP_PIR, Pir_WakeHandle, VHW_IRQ_PIR);

/**
 * @brief: 低功耗定时器回调函数
 * @note: 只在IRQ为低电平的时候采集基础数据
 * @param {uint32_t} dev
 * @return {*}
 */
static int32_t Pir_TimedWakeupHandle(uint32_t dev)
{
    int16_t filter_delta = 0;
    uint16_t adc_result = PIR_GetVoltage();
    if (PIR_ReadGPIO() == false )//中断脚在低电平时才更新长期累积值
    { 
        accumulated_long_term_average -= (accumulated_long_term_average / PIR_LONG_TERM_FILTER_RANGE); 
        accumulated_long_term_average += adc_result;  
        printf("long_term_average:%d\r\n",accumulated_long_term_average / PIR_LONG_TERM_FILTER_RANGE);
    }
    return 0;
}
COMPONENT_WAKEUP_EXPORT(COMP_PIR, Pir_TimedWakeupHandle, vTIMER_1); 

/**
 * @brief: PIR检测任务
 * @note:
 * @param {uint32_t} event
 * @return {*}
 */
static uint32_t Pir_Detec_Task(uint32_t event)
{
    __NVRAM static bool first_flag = true;
    /* 系统启动事件 */
    if (event & EVENT_SYS_START)
    {
        OSAL_LOG("PIR task start");
        Device_Enable(VHW_ADC_PIR);
        Device_RegisteredCB(VHW_IRQ_PIR, Pir_IrqHandle);
        Device_ConfigCB(VHW_IRQ_PIR, ENABLE);
        if (first_flag)
        {
            OSAL_EventRepeatCreate(COMP_PIR,EVENT_PIR_START,30,EVT_PRIORITY_LOW);
            first_flag = false;
        }
        else
        {
            OSAL_EventRepeatCreate(COMP_PIR,EVENT_PIR_PRO,30,EVT_PRIORITY_LOW);     
        }
        // OSAL_SetTaskStatus(TASK_STA_ACTIVE);
        return (event ^ EVENT_SYS_START);
    }

    /* 系统休眠事件 */
    if (event & EVENT_SYS_SLEEP)
    {
        printf("PIR task sleep\r\n");
        Device_ConfigCB(VHW_IRQ_PIR, DISABLE);
        return (event ^ EVENT_SYS_SLEEP);
    }

    if (event & EVENT_PIR_START)
    {
        Warm_UpAnd_FilterCreation();
        return (event ^ EVENT_PIR_START);   
    }

    if (event & EVENT_PIR_PRO)
    {
        Update_AverageFilters();
        return (event ^ EVENT_PIR_PRO);   
    }
    return 0;
}
COMPONENT_TASK_EXPORT(COMP_PIR, Pir_Detec_Task, 0);
